package com.ztesoft.zsmart.zcm.metrics.utils;

import com.ztesoft.zsmart.core.exception.BaseAppException;
import com.ztesoft.zsmart.core.log.ZSmartLogger;
import com.ztesoft.zsmart.core.util.JsonUtil;
import com.ztesoft.zsmart.zcm.core.remote.RestClient;
import com.ztesoft.zsmart.zcm.metrics.config.MetricsStorageProperties;
import com.ztesoft.zsmart.zcm.metrics.model.cmdb.ServerWithClusterIdAndZoneId;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public final class ClusterIpCache implements Runnable {

    /** The Constant logger. */
    private static final ZSmartLogger logger = ZSmartLogger.getLogger(ClusterIpCache.class);

    private static Map<String, Object> cacheMap = new HashMap<>();

    private int refreshTime = SpringContextUtil.getBean(MetricsStorageProperties.class).getClusterRefreshTime();

    private static String cmdbUrl;

    // 读写锁， 写指标时读， 刷新的时候写
    private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    @Override
    public void run() {
        while (true) {
            fresh();
            // 等待刷新
            try {
                Thread.sleep(refreshTime * 60 * 1000L);
            }
            catch (InterruptedException e) {
                logger.error("refresh cluster-ip cache error:", e);
            }
        }
    }

    public static String getClusterIdByIp(String ip) {
        String clusterId = "";
        try {
            lock.readLock().lock();
            if (MapUtils.isEmpty(cacheMap) || cacheMap.get(ip) == null) {
                clusterId = "#-1#";
            }
            else {
                clusterId = String.valueOf(cacheMap.get(ip));
            }

        }
        catch (Exception e) {
            logger.error("read cluster-ip cache error:", e);
        }
        finally {
            lock.readLock().unlock();
        }
        return clusterId;
    }

    public static void refresh() {
        fresh();
    }

    private static void fresh() {
        Map<String, Object> cacheMapTemp = getCacheMap();
        try {
            lock.writeLock().lock();
            if (MapUtils.isNotEmpty(cacheMapTemp)) {
                cacheMap.clear();
                cacheMap.putAll(cacheMapTemp);
            }
        }
        catch (Exception e) {
            logger.error("refresh cluster-ip cache error:", e);
        }
        finally {
            lock.writeLock().unlock();
        }
    }

    private static Map<String, Object> getCacheMap() {
        Map<String, Object> cacheMapTemp = new HashMap<>();
        try {
            logger.info("start refresh cluster-ip cache");
            if (cmdbUrl == null) {
                cmdbUrl = SpringContextUtil.getBean(MetricsStorageProperties.class).getCmdbBaseUrl()
                    + "/rpc/server/qryAllServerWithClusterAndZone";
            }
            Map resp = SpringContextUtil.getBean(RestClient.class).getForObject(cmdbUrl, Map.class);
            if (MapUtils.isNotEmpty(resp)) {
                Map data = (Map) resp.get("data");
                List<Map> content = (List) data.get("content");
                List<ServerWithClusterIdAndZoneId> result = new ArrayList<>();
                content.forEach(c -> {
                    try {
                        result.add(JsonUtil.json2Object(JsonUtil.map2Json(c), ServerWithClusterIdAndZoneId.class));
                    }
                    catch (BaseAppException e) {
                        logger.error(e);
                    }
                });
                result.stream().forEach((ServerWithClusterIdAndZoneId server) -> {
                    String key = server.getServer().getIpAddr();
                    List<Integer> clusterIdList = server.getClusterIdList();
                    List<Integer> zoneIdList = server.getZoneIdList();

                    StringBuffer tag = new StringBuffer();
                    if (CollectionUtils.isNotEmpty(clusterIdList)) {
                        clusterIdList.stream().forEach(c -> tag.append("#").append(c).append("#"));
                    }
                    if (CollectionUtils.isNotEmpty(zoneIdList)) {
                        zoneIdList.stream().forEach(z -> tag.append("#zone_").append(z).append("#"));
                    }
                    if (tag.length() > 0) {
                        cacheMapTemp.put(key, tag.toString());
                    }
                    else {
                        cacheMapTemp.put(key, "#-1#");
                    }
                }

                );
            }

        }
        catch (

        Exception e) {
            logger.error("get cluster cacheMap error:", e);
        }
        return cacheMapTemp;
    }
}
